﻿using LightCAD.Core;
using LightCAD.Core.Elements;
using LightCAD.Runtime;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using WeifenLuo.WinFormsUI.Docking;
using static System.Reflection.Metadata.BlobBuilder;

namespace LightCAD.UI
{
    public partial class PropertyControl2 : DockContent, IPropertyControl
    {
        private Dictionary<ElementType, List<LcElement>> grpEles;
        private List<PropertyObserver> eleObservers;
        private Dictionary<ElementType, List<PropertyObserver>> eleTypeObservers;
        private List<PropertyObserver> mergeAll;
        private Action<List<LcElement>> propertyChangedAction;

        private List<LcElement> curEles;
        public PropertyControl2()
        {
            InitializeComponent();
            this.btnEditCptDef.Enabled = false;
        }

        public void SelectsChanged(Dictionary<ElementType, List<LcElement>> grpEles, List<PropertyObserver> eleObservers, Dictionary<ElementType, List<PropertyObserver>> eleTypeObservers, List<PropertyObserver> mergeAll, Action<List<LcElement>> propertyChangedAction)
        {
            this.propertyGrid.SelectedObject = null;
            this.propertyGrid.Refresh();
            this.btnEditCptDef.Enabled = false;

            this.cboEleTypes.Items.Clear();
            this.cboEleTypes.Text = "无选择";
            if (grpEles.Count == 0)
            {
                return;
            }

            this.grpEles = grpEles;
            this.eleObservers = eleObservers;
            this.eleTypeObservers = eleTypeObservers;
            this.mergeAll = mergeAll;
            this.propertyChangedAction = propertyChangedAction;

            BindTypeName();
        }
        public void PropertyChanged(Dictionary<ElementType, List<LcElement>> grpEles, List<PropertyObserver> eleObservers, Dictionary<ElementType, List<PropertyObserver>> eleTypeObservers, List<PropertyObserver> mergeAll, Action<List<LcElement>> propertyChangedAction)
        {
            this.propertyGrid.SelectedObject = null;
            this.propertyGrid.Refresh();

            this.cboEleTypes.Items.Clear();
            this.cboEleTypes.Text = "无选择";
            if (grpEles.Count == 0)
            {
                return;
            }

            this.grpEles = grpEles;
            this.eleObservers = eleObservers;
            this.eleTypeObservers = eleTypeObservers;
            this.mergeAll = mergeAll;
            this.propertyChangedAction = propertyChangedAction;

            BindTypeName();
        }

        private void BindTypeName()
        {
            if (grpEles.Keys.Count > 1)
            {
                int allTypeCount = this.grpEles.Sum(t => t.Value.Count);
                this.cboEleTypes.Items.Add($"全部({allTypeCount})");
            }
            foreach (var kvp in grpEles)
            {
                string typeName = $"{kvp.Key.ToDisplayName()}({kvp.Value.Count})";
                this.cboEleTypes.Items.Add(typeName);
            }

            this.cboEleTypes.SelectedIndex = 0;
        }

        private void cboEleTypes_SelectedIndexChanged(object sender, EventArgs e)
        {
            //this.dgvProps.CellValueChanged -= dgvProps_CellValueChanged;
            //this.dgvProps.Rows.Clear();
            string selEleType = this.cboEleTypes.Text;

            if (selEleType.StartsWith("全部"))
            {
                var observers = eleObservers.Concat(mergeAll).ToList();
                this.curEles = this.grpEles.SelectMany(P => P.Value).ToList();
                BindProperties(this.curEles, observers);
                return;
            }

            this.curEles = this.grpEles.FirstOrDefault(G => selEleType.StartsWith(G.Key.ToDisplayName())).Value;
            var selObs = this.eleTypeObservers.FirstOrDefault(G => selEleType.StartsWith(G.Key.ToDisplayName())).Value;
            selObs = eleObservers.Concat(selObs).ToList();
            BindProperties(this.curEles, selObs);

            //this.dgvProps.CellValueChanged += dgvProps_CellValueChanged;
        }

        private void BindProperties(List<LcElement> eles, List<PropertyObserver> obs)
        {
            var elePropDic = new Dictionary<string, object>();
            foreach (PropertyObserver tmpOb in obs)
            {
                //不同的Element会存在相同的属性名称，这样在前面去重时只会保留一个PropertyObserver
                //所以这里根据ElementType和PropertyObserver的名称找到应当前元素对应的PropertyObserver
                foreach (LcElement ele in eles)
                {
                    var ob = GetObserver(ele, tmpOb);
                    var propValue = ob.Getter(ele);
                    if (propValue == null)
                    {
                        continue;
                    }
                    if (ob.PropType == PropertyType.Array)
                    {
                        var source = ob.Source(ele);
                        propValue = Tuple.Create(propValue, source);
                    }
                    if (!elePropDic.ContainsKey(ob.DisplayName))
                    {
                        elePropDic.Add(ob.DisplayName, propValue);
                        continue;
                    }

                    if (!elePropDic[ob.DisplayName].Equals(propValue))
                    {
                        elePropDic[ob.DisplayName] = "*多种*";
                        break;
                    }
                }
            }

            int i = 0;

            PropertyManageCls pmc = new PropertyManageCls();

            foreach (var kvp in elePropDic)
            {
                var curOb = obs[i];
                var val = kvp.Value;
                object[] source = null;
                if (val is Tuple<object, object> tuple)
                {
                    val = tuple.Item1;
                    source = tuple.Item2 as object[];
                }

                var obj = new PropObject(kvp.Key, val)
                {
                    Category = curOb.CategoryDisplayName,
                    DisplayName = kvp.Key,
                    ReadOnly = curOb.Setter == null,
                    Tag = curOb,
                };

                if (curOb.PropType == PropertyType.Array)
                {
                    //obj.Value = Color.Red;
                    obj.Converter = new DropDownListConverter(source);
                }

                if (curOb.PropType == PropertyType.Double)
                {
                    //obj.Value = Color.Red;
                    obj.Converter = new DoubleConverter();
                }
                bool isOk = pmc.Add(obj);
                i++;
            }

            this.propertyGrid.SelectedObject = pmc;
            this.propertyGrid.Refresh();

            if (eles.Count == 1 && (eles[0] is IComponentInstance))
            {
                this.btnEditCptDef.Enabled = true;
            }
            else
            {
                this.btnEditCptDef.Enabled = false;
            }
        }

        //private void dgvProps_CellValueChanged(object sender, DataGridViewCellEventArgs e)
        //{
        //    var dr = this.dgvProps.Rows[e.RowIndex];
        //    var ob = dr.Tag as PropertyObserver;
        //    var newValue = dr.Cells[e.ColumnIndex].Value;

        //    foreach (var ele in this.curEles)
        //    {
        //        ob.Setter(ele, newValue);
        //    }

        //    this.propertyChangedAction?.Invoke(curEles);
        //}

        private void propertyGrid_PropertyValueChanged(object s, PropertyValueChangedEventArgs e)
        {
            string oldValue = e.OldValue.ToString();
            string newValue = e.ChangedItem.Value.ToString();
            if (newValue == oldValue) //未修改值
                return;

            string propName = e.ChangedItem.Label;
            var descriptor = e.ChangedItem.PropertyDescriptor as CustomPropertyDescriptor;
            var propObj = descriptor.PropObj;
            var tempOb = propObj.Tag as PropertyObserver;
            foreach (var ele in this.curEles)
            {
                var ob = GetObserver(ele, tempOb);
                ob.Setter(ele, newValue);
            }

            this.propertyChangedAction?.Invoke(curEles);
        }

        public PropertyObserver GetObserver(LcElement ele, PropertyObserver tmpOb)
        {
            var ob = this.eleTypeObservers.FirstOrDefault(p => p.Key.ToDisplayName() == ele.Type.ToDisplayName())
                                          .Value
                                          .FirstOrDefault(p => p.DisplayName == tmpOb.DisplayName);
            if (ob == null) //元素基类上的属性，通过ElementType找不到
                ob = tmpOb;

            return ob;
        }

        private void btnEditCptDef_Click(object sender, EventArgs e)
        {
            var cpt = this.curEles[0] as IComponentInstance;
            CptDefPropertyControl form = new CptDefPropertyControl(cpt);
            form.ShowDialog();
        }
    }
}